Carmen Martín Turrero


Date : 10/05/2022


library(lubridate)
library(ggplot2)
library(GoFKernel)
library(latex2exp)
library(dplyr)
library(plotly)

Exercise 1

The number of particles emitted by a radioactive source during a fixed interval of time (∆t = 10 s) follows a Poisson distribution on the parameter µ. The number of particles observed during consecutive time intervals is: 4, 1, 3, 1 and 3

  1. suppose a uniform prior distribution for the parameter µ
# Data
t.int <- 10 #s
x.observed <- c(4, 1, 3, 1, 3)

# Uniform prior
x <- seq(0, 10, by=0.01)
U.prior <- dgamma(x, 1, 0)

# the posterior is a gamma function with parameters:
U.alpha <- sum(x.observed) + 1
U.lambda <- length(x.observed)

U.posterior <- dgamma(x, U.alpha, U.lambda)

uni.df <- data.frame(x = x, prior = U.prior+0.1, posterior = U.posterior)

uni.plot <- ggplot() +
  geom_line(data = uni.df, aes(x = x, y = prior, color = 'Uniform prior'), linetype =2 , size = 0.8) +
  geom_line(data = uni.df, aes(x = x, y = posterior, color = 'Posterior'), size = 0.8) +
  labs(title = 'Particles emitted by radioactive source during 10s', subtitle = 'Poisson Distribution', x = 'n', y = 'PDF') +
  guides(color=guide_legend(NULL, order = 5)) +
  scale_colour_brewer(palette = "Paired")

uni.plot

# Analytically
aU.mean <- (U.alpha-1)/U.lambda
aU.var <- (U.alpha-1)/(U.lambda**2)

# Numerically
nU.mean <- integrate(function(x) {x*dgamma(x, U.alpha, U.lambda)}, 0, 10)
Ex2 <- integrate(function(x) {(x**2)*dgamma(x, U.alpha, U.lambda)}, 0, 10)
nU.var <- Ex2$value - (nU.mean$value)**2

# We use the quantile to obtain the median
nU.median <- qgamma(0.5, U.alpha, U.lambda)

message('Analytically: mean = ', aU.mean, ', variance = ', aU.var)
Analytically: mean = 2.4, variance = 0.48
message('Numerically: mean = ', round(nU.mean$value,2), ', variance = ', round(nU.var,2))
Numerically: mean = 2.6, variance = 0.52
message('Median = ', round(nU.median,2))
Median = 2.53
  1. suppose a Jeffrey’s prior for the parameter µ
# Jeffreys prior
x <- seq(0, 10, by=0.01)
J.prior <- dgamma(x, 0.5, 0)

# the posterior is a gamma function with parameters:
J.alpha <- sum(x.observed) + 0.5
J.lambda <- length(x.observed)

J.posterior <- dgamma(x, J.alpha, J.lambda)

jef.df <- data.frame(x = x, prior = J.prior, posterior = J.posterior)

jef.plot <- ggplot() +
  geom_line(data = jef.df, aes(x = x, y = prior, color = 'Jeffreys prior'), linetype =2 , size = 0.8) +
  geom_line(data = jef.df, aes(x = x, y = posterior, color = 'Posterior'), size = 0.8) +
  labs(title = 'Particles emitted by radioactive source during 10s', subtitle = 'Poisson Distribution', x = 'n', y = 'PDF') +
  guides(color=guide_legend(NULL, order = 5)) +
  scale_colour_brewer(palette = "Paired")

jef.plot

# Analytically
aJ.mean <- (J.alpha-0.5)/J.lambda
aJ.var <- (J.alpha-0.5)/(J.lambda**2)

# Numerically
nJ.mean <- integrate(function(x) {x*dgamma(x, J.alpha, J.lambda)}, 0, 10)
Ex2 <- integrate(function(x) {(x**2)*dgamma(x, J.alpha, J.lambda)}, 0, 10)
nJ.var <- Ex2$value - (nJ.mean$value)**2

# We use the quantile to obtain the median
nJ.median <- qgamma(0.5, J.alpha, J.lambda)

message('Analytically: mean = ', aJ.mean, ', variance = ', aJ.var)
Analytically: mean = 2.4, variance = 0.48
message('Numerically: mean = ', round(nJ.mean$value,2), ', variance = ', round(nJ.var,2))
Numerically: mean = 2.5, variance = 0.5
message('Median = ', round(nJ.median,2))
Median = 2.43
  1. evaluate a 95% credibility interval for the results obtained with both priors. Compare the result with that obtained using a normal approximation for the posterior distribution, with the same mean and standard deviation
# Most probable value 
max.valueU <- x[which.max(U.posterior)]
max.valueJ <- x[which.max(J.posterior)]

# Credibility intervals
U.x1 <- qgamma(0.025, U.alpha, U.lambda)   
U.x2 <- qgamma(0.975, U.alpha, U.lambda)
print(paste0('Uniform prior credibility interval of [', round(U.x1,2),', ', round(U.x2,2),']'))
[1] "Uniform prior credibility interval of [1.38, 4.19]"
J.x1 <- qgamma(0.025, J.alpha, J.lambda)   
J.x2 <- qgamma(0.975, J.alpha, J.lambda)
print(paste0('Jeffreys prior credibility interval of [', round(J.x1,2),', ', round(J.x2,2),']'))
[1] "Jeffreys prior credibility interval of [1.31, 4.06]"
G.x1 <- qnorm(0.025, aU.mean, sqrt(aU.var))
G.x2 <- qnorm(0.975, aU.mean, sqrt(aU.var))
print(paste0('Normal approximation credibility interval of [', round(G.x1,2),', ', round(G.x2,2),']'))
[1] "Normal approximation credibility interval of [1.04, 3.76]"

Exercise 2

Given the problem of the lightouse discussed last week, study the case in which both the position along the shore (α) and the distance out at sea (β) are unknown.

As discussed during the lectures, it is reasonable to assign a uniform likelihood on the azimuth angle \(\theta_k\) , given the angle is uniform over \(\pm \pi/2\), the probability is:

\[\begin{equation} P(X |\alpha,\beta) = \frac{1}{\pi} \end{equation}\]

\(\theta_k\) is connected to the distances \(\alpha\) and \(\beta\) through the relation

\[\begin{equation} x_k - \alpha = \beta \tan \theta_k \end{equation}\]

We can perform a change of variable in order to compute \(P(x|\alpha,\beta)\):

\[\begin{equation} P(x|\alpha,\beta) = P(\theta|\alpha,\beta)\abs{\frac{d\theta}{dx}} \end{equation}\]

Since \(x=\beta \tan\theta + \alpha\), by differenciating \(\theta\) w.r.t. \(x\), we obtain:

\[\begin{equation} \abs{\frac{d\theta}{dx}} = \frac{\beta^2 + (x - \alpha)^2}{\beta} \end{equation}\]

And, as a consequence:

\[\begin{equation} P(x|\alpha,\beta) = \frac{1}{\pi}\frac{\beta}{\beta^2 + (x - \alpha)^2} \end{equation}\]

This pdf corresponds to the Cauchy distribution.

Now, since we do not know \(\alpha\) nor \(\beta\), we estimate their prior. As \(\alpha \perp \beta\), the posterior is of the form:

\[\begin{equation} P(\alpha,\beta |{x_k}) \propto P({x_k}|\alpha,\beta)P(\alpha)P(\beta) \end{equation}\]

Assuming \(\alpha\) is uniform over the segment \([x_{min},\ x_{max}]\), i.e. \(p(\alpha) = \frac{1}{x_{max} - x_{min}}\); and \(\beta\) is uniform over the segment \([0, y_{max}]\), i.e. \(p(\beta) = \frac{1}{y_{max}}\). Then, the posterior is proportional to the likelihood:

\[\begin{equation} P(\alpha,\beta |{x_k}) \propto P({x_k}|\alpha,\beta) \end{equation}\]

For the likelihood, we consider each sample of the data to be iid and, therefore:

\[\begin{equation} P({x_k}|\alpha,\beta) = \prod_{k=1}^{N} P(x_k|\alpha,\beta) \end{equation}\]
# Generate dataset
set.seed(4183)
# true values
a <- 10; b <- 10;
N <- 200
theta <- runif(N, -pi/2, pi/2)
x.k <- a*tan(theta) + a
#Set the problem data
x.min <- -2000 #m
x.max <- 2000 #m
y.max <- 5000 #m

alphas <- seq(x.min, x.max, 20)
betas <- seq(0, y.max, 20)
# Logarithmic posterior
log.posterior <- function(x.k, alph, bet) {
  sum(log((bet)/(pi*(bet**2 + (x.k-alph)**2))))
}

f.aux <- function (a, b){ log.posterior(x.k, a, b) }

# Evaluate for all possible parameter combinations 
log.grid <- outer(alphas, betas, Vectorize(f.aux))

# Posteriors shape
# Individual posterior (known alpha)
log.posterior.ind <- function (x.k, b) {
  Vectorize(function(a_) {
    sum(log(b/(pi*(b**2 + (x.k-a_)**2))))
  })
}

lpos <- log.posterior.ind(x.k, a)

# Normalize and exponentiate
shape.posterior <- function (x, lpos) {
  log.alphas <- lpos(x)
  log.maxalpha <- max(log.alphas)
  return (exp(log.alphas - log.maxalpha))
}

# Obtain the results
grid.values <- matrix(shape.posterior(log.grid, lpos), 
                      nrow = length(alphas), ncol = length(betas))
fig <- plot_ly(type = 'surface',x = alphas, y = betas, z = grid.values)
fig <- layout(fig, scene = list(yaxis = list(title = 'Height (m)',range=c(1900,2100)), xaxis = list(title = 'Location (m)',range = c(-2000,-1900)), zaxis = list(title = 'PDF')))

fig

max = which(grid.values == max(grid.values), arr.ind = TRUE)
max.alpha <- alphas[max[1,2]]
max.beta <- betas[max[1,1]]
message('The position of the lighthouse is ', (max.alpha)/1000,'km along the shore and ', max.beta/1000, 'km out at sea.')
The position of the lighthouse is -1.98km along the shore and 2.02km out at sea.

Exercise 3

Given the Signal over Background example discussed last week, analyze and discuss the following cases:

  1. vary the sampling resolution of used to generate the data, keeping the same sampling range xdat <- seq(from=-7w, to=7w, by=0.5*w) • change the resolution w = {0.1, 0.25, 1, 2, 3} • Check the effect on the results
# Generative model
signal <- function(x, a, b, x0, w, t) {
  t * (a*exp(-((x-x0)**2)/(2*w**2)) + b)
}

# Define model parameters
x0 <- 0 # Signal peak
w.range <- c(0.1, 0.25, 1, 2, 3) # Signal width
A.true <- 2 # Signal amplitude
B.true <- 1 # Background amplitude
Delta.t <- 5 # Exposure time

# Sampling grid for computing posterior
alim <- c(0.0, 4.0)
blim <- c(0.5, 1.5)
Nsamp <- 100
uniGrid <- seq(from=1/(2*Nsamp),
to=1-1/(2*Nsamp), by=1/Nsamp)
delta_a <- diff(alim )/ Nsamp
delta_b <- diff(blim )/ Nsamp
a <- alim[1] + diff(alim )* uniGrid
b <- blim[1] + diff(blim )* uniGrid

# Log posterior
log.post <- function(d, x, a, b, x0, w, t) {
  if(a<0 || b <0) {return(-Inf )} # the effect of the prior
  sum(dpois(d, lambda=signal(x, a, b, x0, w, t), log=TRUE))
}

# Generate the observed data
set.seed(123)
for (w in w.range){
  xdat <- seq(from=-7*w, to=7*w, by=0.5*w)
  
  s.true <- signal(xdat , A.true , B.true , x0, w, Delta.t)
  ddat <- rpois(length(s.true), s.true)
  xplot <- seq(from=min(xdat), to=max(xdat), by=0.05*w)
  splot <- signal(xplot , A.true , B.true , x0, w, Delta.t)
  options(repr.plot.width=14, repr.plot.height=10)  #to set graph size
  par(mfrow=c(1,2))
  plot(xplot , splot , xlab="x", ylab="Signal+Background counts", ylim=c(2, 24))
  #par(new=TRUE)
  xdat.off <- xdat - 0.25
  lines(xdat.off, ddat , type='s',col='firebrick3', lwd=2,xlim=range(xplot), ylim=range(c(splot , ddat )))
  
  # Compute log unnormalized posterior , z = ln Pˆ*(a,b|D), on a regular grid
  z <- matrix(data=NA , nrow=length(a), ncol=length(b))
  for(j in 1:length(a)) {
    for(k in 1:length(b)) {
      z[j,k] <- log.post(ddat , xdat , a[j], b[k], x0, w, Delta.t)
    }
  }
  z <- z - max(z) # set maximum to zero
  # Plot unnormalized 2D posterior as contours.
  contour(a, b, exp(z),
          nlevels = 5,
          labcex = 0.5,
          lwd = 2,
          xlab="amplitude , A",
          ylab="background , B")
  abline(v=2,h=1,col="grey")
}

NA
NA
  1. change the ratio A/B used to simulate the data (keeping both positive in accordance with the prior) • Check the effect on the results

# Define model parameters
x0 <- 0 # Signal peak
w.range <- 1 # Signal width
A.true <- 4 # Signal amplitude
B.true <- 1 # Background amplitude
Delta.t <- 5 # Exposure time

xdat <- seq(from=-7*w, to=7*w, by=0.5*w)
  
s.true <- signal(xdat , A.true , B.true , x0, w, Delta.t)
ddat <- rpois(length(s.true), s.true)
xplot <- seq(from=min(xdat), to=max(xdat), by=0.05*w)
splot <- signal(xplot , A.true , B.true , x0, w, Delta.t)
options(repr.plot.width=14, repr.plot.height=10)  #to set graph size
par(mfrow=c(1,2))
plot(xplot , splot , xlab="x", ylab="Signal+Background counts", ylim=c(0, 40))
#par(new=TRUE)
xdat.off <- xdat - 0.25
lines(xdat.off, ddat , type='s',col='firebrick3', lwd=2,xlim=range(xplot), ylim=range(c(splot , ddat )))

# Compute log unnormalized posterior , z = ln Pˆ*(a,b|D), on a regular grid
z <- matrix(data=NA , nrow=length(a), ncol=length(b))
for(j in 1:length(a)) {
  for(k in 1:length(b)) {
    z[j,k] <- log.post(ddat , xdat , a[j], b[k], x0, w, Delta.t)
  }
}
z <- z - max(z) # set maximum to zero
# Plot unnormalized 2D posterior as contours.
contour(a, b, exp(z),
        nlevels = 4,
        labcex = 0.5,
        lwd = 2,
        xlab="amplitude , A",
        ylab="background , B",
        xlim = c(0,5))
abline(v=4,h=1,col="grey")

NA
NA
LS0tDQp0aXRsZTogIkxhYm9yYXRvcnkgMDUiDQpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sNCmVkaXRvcl9vcHRpb25zOiANCiAgbWFya2Rvd246IA0KICAgIHdyYXA6IDcyDQotLS0NCg0KQ2FybWVuIE1hcnTDrW4gVHVycmVybw0KDQotLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0NCg0KRGF0ZSA6IDEwLzA1LzIwMjINCg0KLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tDQoNCmBgYHtyfQ0KbGlicmFyeShsdWJyaWRhdGUpDQpsaWJyYXJ5KGdncGxvdDIpDQpsaWJyYXJ5KEdvRktlcm5lbCkNCmxpYnJhcnkobGF0ZXgyZXhwKQ0KbGlicmFyeShkcGx5cikNCmxpYnJhcnkocGxvdGx5KQ0KYGBgDQoNCi0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQ0KDQojIyBFeGVyY2lzZSAxDQoNClRoZSBudW1iZXIgb2YgcGFydGljbGVzIGVtaXR0ZWQgYnkgYSByYWRpb2FjdGl2ZSBzb3VyY2UgZHVyaW5nIGEgZml4ZWQNCmludGVydmFsIG9mIHRpbWUgKOKIhnQgPSAxMCBzKSBmb2xsb3dzIGEgUG9pc3NvbiBkaXN0cmlidXRpb24gb24gdGhlDQpwYXJhbWV0ZXIgwrUuIFRoZSBudW1iZXIgb2YgcGFydGljbGVzIG9ic2VydmVkIGR1cmluZyBjb25zZWN1dGl2ZSB0aW1lDQppbnRlcnZhbHMgaXM6IDQsIDEsIDMsIDEgYW5kIDMNCg0KKGEpIHN1cHBvc2UgYSB1bmlmb3JtIHByaW9yIGRpc3RyaWJ1dGlvbiBmb3IgdGhlIHBhcmFtZXRlciDCtQ0KDQotICAgZGV0ZXJtaW5lIGFuZCBkcmF3IHRoZSBwb3N0ZXJpb3IgZGlzdHJpYnV0aW9uIGZvciDCtSwgZ2l2ZW4gdGhlIGRhdGENCi0gICBldmFsdWF0ZSBtZWFuLCBtZWRpYW4gYW5kIHZhcmlhbmNlLCBib3RoIGFuYWx5dGljYWxseSBhbmQNCiAgICBudW1lcmljYWxseSBpbiBSDQoNCmBgYHtyfQ0KIyBEYXRhDQp0LmludCA8LSAxMCAjcw0KeC5vYnNlcnZlZCA8LSBjKDQsIDEsIDMsIDEsIDMpDQoNCiMgVW5pZm9ybSBwcmlvcg0KeCA8LSBzZXEoMCwgMTAsIGJ5PTAuMDEpDQpVLnByaW9yIDwtIGRnYW1tYSh4LCAxLCAwKQ0KDQojIHRoZSBwb3N0ZXJpb3IgaXMgYSBnYW1tYSBmdW5jdGlvbiB3aXRoIHBhcmFtZXRlcnM6DQpVLmFscGhhIDwtIHN1bSh4Lm9ic2VydmVkKSArIDENClUubGFtYmRhIDwtIGxlbmd0aCh4Lm9ic2VydmVkKQ0KDQpVLnBvc3RlcmlvciA8LSBkZ2FtbWEoeCwgVS5hbHBoYSwgVS5sYW1iZGEpDQoNCnVuaS5kZiA8LSBkYXRhLmZyYW1lKHggPSB4LCBwcmlvciA9IFUucHJpb3IrMC4xLCBwb3N0ZXJpb3IgPSBVLnBvc3RlcmlvcikNCg0KdW5pLnBsb3QgPC0gZ2dwbG90KCkgKw0KICBnZW9tX2xpbmUoZGF0YSA9IHVuaS5kZiwgYWVzKHggPSB4LCB5ID0gcHJpb3IsIGNvbG9yID0gJ1VuaWZvcm0gcHJpb3InKSwgbGluZXR5cGUgPTIgLCBzaXplID0gMC44KSArDQogIGdlb21fbGluZShkYXRhID0gdW5pLmRmLCBhZXMoeCA9IHgsIHkgPSBwb3N0ZXJpb3IsIGNvbG9yID0gJ1Bvc3RlcmlvcicpLCBzaXplID0gMC44KSArDQogIGxhYnModGl0bGUgPSAnUGFydGljbGVzIGVtaXR0ZWQgYnkgcmFkaW9hY3RpdmUgc291cmNlIGR1cmluZyAxMHMnLCBzdWJ0aXRsZSA9ICdQb2lzc29uIERpc3RyaWJ1dGlvbicsIHggPSAnbicsIHkgPSAnUERGJykgKw0KICBndWlkZXMoY29sb3I9Z3VpZGVfbGVnZW5kKE5VTEwsIG9yZGVyID0gNSkpICsNCiAgc2NhbGVfY29sb3VyX2JyZXdlcihwYWxldHRlID0gIlBhaXJlZCIpDQoNCnVuaS5wbG90DQpgYGANCg0KYGBge3J9DQojIEFuYWx5dGljYWxseQ0KYVUubWVhbiA8LSAoVS5hbHBoYS0xKS9VLmxhbWJkYQ0KYVUudmFyIDwtIChVLmFscGhhLTEpLyhVLmxhbWJkYSoqMikNCg0KIyBOdW1lcmljYWxseQ0KblUubWVhbiA8LSBpbnRlZ3JhdGUoZnVuY3Rpb24oeCkge3gqZGdhbW1hKHgsIFUuYWxwaGEsIFUubGFtYmRhKX0sIDAsIDEwKQ0KRXgyIDwtIGludGVncmF0ZShmdW5jdGlvbih4KSB7KHgqKjIpKmRnYW1tYSh4LCBVLmFscGhhLCBVLmxhbWJkYSl9LCAwLCAxMCkNCm5VLnZhciA8LSBFeDIkdmFsdWUgLSAoblUubWVhbiR2YWx1ZSkqKjINCg0KIyBXZSB1c2UgdGhlIHF1YW50aWxlIHRvIG9idGFpbiB0aGUgbWVkaWFuDQpuVS5tZWRpYW4gPC0gcWdhbW1hKDAuNSwgVS5hbHBoYSwgVS5sYW1iZGEpDQoNCm1lc3NhZ2UoJ0FuYWx5dGljYWxseTogbWVhbiA9ICcsIGFVLm1lYW4sICcsIHZhcmlhbmNlID0gJywgYVUudmFyKQ0KbWVzc2FnZSgnTnVtZXJpY2FsbHk6IG1lYW4gPSAnLCByb3VuZChuVS5tZWFuJHZhbHVlLDIpLCAnLCB2YXJpYW5jZSA9ICcsIHJvdW5kKG5VLnZhciwyKSkNCm1lc3NhZ2UoJ01lZGlhbiA9ICcsIHJvdW5kKG5VLm1lZGlhbiwyKSkNCmBgYA0KDQooYikgc3VwcG9zZSBhIEplZmZyZXkncyBwcmlvciBmb3IgdGhlIHBhcmFtZXRlciDCtQ0KDQotICAgZGV0ZXJtaW5lIGFuZCBkcmF3IHRoZSBwb3N0ZXJpb3IgZGlzdHJpYnV0aW9uIGZvciDCtSwgZ2l2ZW4gdGhlIGRhdGENCi0gICBldmFsdWF0ZSBtZWFuLCBtZWRpYW4gYW5kIHZhcmlhbmNlLCBib3RoIGFuYWx5dGljYWxseSBhbmQNCiAgICBudW1lcmljYWxseSBpbiBSDQoNCmBgYHtyfQ0KIyBKZWZmcmV5cyBwcmlvcg0KeCA8LSBzZXEoMCwgMTAsIGJ5PTAuMDEpDQpKLnByaW9yIDwtIGRnYW1tYSh4LCAwLjUsIDApDQoNCiMgdGhlIHBvc3RlcmlvciBpcyBhIGdhbW1hIGZ1bmN0aW9uIHdpdGggcGFyYW1ldGVyczoNCkouYWxwaGEgPC0gc3VtKHgub2JzZXJ2ZWQpICsgMC41DQpKLmxhbWJkYSA8LSBsZW5ndGgoeC5vYnNlcnZlZCkNCg0KSi5wb3N0ZXJpb3IgPC0gZGdhbW1hKHgsIEouYWxwaGEsIEoubGFtYmRhKQ0KDQpqZWYuZGYgPC0gZGF0YS5mcmFtZSh4ID0geCwgcHJpb3IgPSBKLnByaW9yLCBwb3N0ZXJpb3IgPSBKLnBvc3RlcmlvcikNCg0KamVmLnBsb3QgPC0gZ2dwbG90KCkgKw0KICBnZW9tX2xpbmUoZGF0YSA9IGplZi5kZiwgYWVzKHggPSB4LCB5ID0gcHJpb3IsIGNvbG9yID0gJ0plZmZyZXlzIHByaW9yJyksIGxpbmV0eXBlID0yICwgc2l6ZSA9IDAuOCkgKw0KICBnZW9tX2xpbmUoZGF0YSA9IGplZi5kZiwgYWVzKHggPSB4LCB5ID0gcG9zdGVyaW9yLCBjb2xvciA9ICdQb3N0ZXJpb3InKSwgc2l6ZSA9IDAuOCkgKw0KICBsYWJzKHRpdGxlID0gJ1BhcnRpY2xlcyBlbWl0dGVkIGJ5IHJhZGlvYWN0aXZlIHNvdXJjZSBkdXJpbmcgMTBzJywgc3VidGl0bGUgPSAnUG9pc3NvbiBEaXN0cmlidXRpb24nLCB4ID0gJ24nLCB5ID0gJ1BERicpICsNCiAgZ3VpZGVzKGNvbG9yPWd1aWRlX2xlZ2VuZChOVUxMLCBvcmRlciA9IDUpKSArDQogIHNjYWxlX2NvbG91cl9icmV3ZXIocGFsZXR0ZSA9ICJQYWlyZWQiKQ0KDQpqZWYucGxvdA0KYGBgDQoNCmBgYHtyfQ0KIyBBbmFseXRpY2FsbHkNCmFKLm1lYW4gPC0gKEouYWxwaGEtMC41KS9KLmxhbWJkYQ0KYUoudmFyIDwtIChKLmFscGhhLTAuNSkvKEoubGFtYmRhKioyKQ0KDQojIE51bWVyaWNhbGx5DQpuSi5tZWFuIDwtIGludGVncmF0ZShmdW5jdGlvbih4KSB7eCpkZ2FtbWEoeCwgSi5hbHBoYSwgSi5sYW1iZGEpfSwgMCwgMTApDQpFeDIgPC0gaW50ZWdyYXRlKGZ1bmN0aW9uKHgpIHsoeCoqMikqZGdhbW1hKHgsIEouYWxwaGEsIEoubGFtYmRhKX0sIDAsIDEwKQ0KbkoudmFyIDwtIEV4MiR2YWx1ZSAtIChuSi5tZWFuJHZhbHVlKSoqMg0KDQojIFdlIHVzZSB0aGUgcXVhbnRpbGUgdG8gb2J0YWluIHRoZSBtZWRpYW4NCm5KLm1lZGlhbiA8LSBxZ2FtbWEoMC41LCBKLmFscGhhLCBKLmxhbWJkYSkNCg0KbWVzc2FnZSgnQW5hbHl0aWNhbGx5OiBtZWFuID0gJywgYUoubWVhbiwgJywgdmFyaWFuY2UgPSAnLCBhSi52YXIpDQptZXNzYWdlKCdOdW1lcmljYWxseTogbWVhbiA9ICcsIHJvdW5kKG5KLm1lYW4kdmFsdWUsMiksICcsIHZhcmlhbmNlID0gJywgcm91bmQobkoudmFyLDIpKQ0KbWVzc2FnZSgnTWVkaWFuID0gJywgcm91bmQobkoubWVkaWFuLDIpKQ0KYGBgDQoNCihjKSBldmFsdWF0ZSBhIDk1JSBjcmVkaWJpbGl0eSBpbnRlcnZhbCBmb3IgdGhlIHJlc3VsdHMgb2J0YWluZWQgd2l0aA0KICAgIGJvdGggcHJpb3JzLiBDb21wYXJlIHRoZSByZXN1bHQgd2l0aCB0aGF0IG9idGFpbmVkIHVzaW5nIGEgbm9ybWFsDQogICAgYXBwcm94aW1hdGlvbiBmb3IgdGhlIHBvc3RlcmlvciBkaXN0cmlidXRpb24sIHdpdGggdGhlIHNhbWUgbWVhbiBhbmQNCiAgICBzdGFuZGFyZCBkZXZpYXRpb24NCg0KYGBge3J9DQojIE1vc3QgcHJvYmFibGUgdmFsdWUgDQptYXgudmFsdWVVIDwtIHhbd2hpY2gubWF4KFUucG9zdGVyaW9yKV0NCm1heC52YWx1ZUogPC0geFt3aGljaC5tYXgoSi5wb3N0ZXJpb3IpXQ0KDQojIENyZWRpYmlsaXR5IGludGVydmFscw0KVS54MSA8LSBxZ2FtbWEoMC4wMjUsIFUuYWxwaGEsIFUubGFtYmRhKSAgIA0KVS54MiA8LSBxZ2FtbWEoMC45NzUsIFUuYWxwaGEsIFUubGFtYmRhKQ0KcHJpbnQocGFzdGUwKCdVbmlmb3JtIHByaW9yIGNyZWRpYmlsaXR5IGludGVydmFsIG9mIFsnLCByb3VuZChVLngxLDIpLCcsICcsIHJvdW5kKFUueDIsMiksJ10nKSkNCg0KSi54MSA8LSBxZ2FtbWEoMC4wMjUsIEouYWxwaGEsIEoubGFtYmRhKSAgIA0KSi54MiA8LSBxZ2FtbWEoMC45NzUsIEouYWxwaGEsIEoubGFtYmRhKQ0KcHJpbnQocGFzdGUwKCdKZWZmcmV5cyBwcmlvciBjcmVkaWJpbGl0eSBpbnRlcnZhbCBvZiBbJywgcm91bmQoSi54MSwyKSwnLCAnLCByb3VuZChKLngyLDIpLCddJykpDQoNCkcueDEgPC0gcW5vcm0oMC4wMjUsIGFVLm1lYW4sIHNxcnQoYVUudmFyKSkNCkcueDIgPC0gcW5vcm0oMC45NzUsIGFVLm1lYW4sIHNxcnQoYVUudmFyKSkNCnByaW50KHBhc3RlMCgnTm9ybWFsIGFwcHJveGltYXRpb24gY3JlZGliaWxpdHkgaW50ZXJ2YWwgb2YgWycsIHJvdW5kKEcueDEsMiksJywgJywgcm91bmQoRy54MiwyKSwnXScpKQ0KDQpgYGANCg0KLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tDQoNCiMjIEV4ZXJjaXNlIDINCg0KR2l2ZW4gdGhlIHByb2JsZW0gb2YgdGhlIGxpZ2h0b3VzZSBkaXNjdXNzZWQgbGFzdCB3ZWVrLCBzdHVkeSB0aGUgY2FzZQ0KaW4gd2hpY2ggYm90aCB0aGUgcG9zaXRpb24gYWxvbmcgdGhlIHNob3JlICjOsSkgYW5kIHRoZSBkaXN0YW5jZSBvdXQgYXQNCnNlYSAozrIpIGFyZSB1bmtub3duLg0KDQpBcyBkaXNjdXNzZWQgZHVyaW5nIHRoZSBsZWN0dXJlcywgaXQgaXMgcmVhc29uYWJsZSB0byBhc3NpZ24gYSB1bmlmb3JtDQpsaWtlbGlob29kIG9uIHRoZSBhemltdXRoIGFuZ2xlICRcdGhldGFfayQgLCBnaXZlbiB0aGUgYW5nbGUgaXMgdW5pZm9ybQ0Kb3ZlciAkXHBtIFxwaS8yJCwgdGhlIHByb2JhYmlsaXR5IGlzOg0KDQpgYGB7PXRleH0NClxiZWdpbntlcXVhdGlvbn0NClAoWCB8XGFscGhhLFxiZXRhKSA9IFxmcmFjezF9e1xwaX0NClxlbmR7ZXF1YXRpb259DQpgYGANCiRcdGhldGFfayQgaXMgY29ubmVjdGVkIHRvIHRoZSBkaXN0YW5jZXMgJFxhbHBoYSQgYW5kICRcYmV0YSQgdGhyb3VnaA0KdGhlIHJlbGF0aW9uDQoNCmBgYHs9dGV4fQ0KXGJlZ2lue2VxdWF0aW9ufQ0KeF9rIC0gXGFscGhhID0gXGJldGEgXHRhbiBcdGhldGFfaw0KXGVuZHtlcXVhdGlvbn0NCmBgYA0KV2UgY2FuIHBlcmZvcm0gYSBjaGFuZ2Ugb2YgdmFyaWFibGUgaW4gb3JkZXIgdG8gY29tcHV0ZQ0KJFAoeHxcYWxwaGEsXGJldGEpJDoNCg0KYGBgez10ZXh9DQpcYmVnaW57ZXF1YXRpb259DQpQKHh8XGFscGhhLFxiZXRhKSA9IFAoXHRoZXRhfFxhbHBoYSxcYmV0YSlcYWJze1xmcmFje2RcdGhldGF9e2R4fX0NClxlbmR7ZXF1YXRpb259DQpgYGANClNpbmNlICR4PVxiZXRhIFx0YW5cdGhldGEgKyBcYWxwaGEkLCBieSBkaWZmZXJlbmNpYXRpbmcgJFx0aGV0YSQgdy5yLnQuDQokeCQsIHdlIG9idGFpbjoNCg0KYGBgez10ZXh9DQpcYmVnaW57ZXF1YXRpb259DQpcYWJze1xmcmFje2RcdGhldGF9e2R4fX0gPSBcZnJhY3tcYmV0YV4yICsgKHggLSBcYWxwaGEpXjJ9e1xiZXRhfQ0KXGVuZHtlcXVhdGlvbn0NCmBgYA0KQW5kLCBhcyBhIGNvbnNlcXVlbmNlOg0KDQpgYGB7PXRleH0NClxiZWdpbntlcXVhdGlvbn0NClAoeHxcYWxwaGEsXGJldGEpID0gXGZyYWN7MX17XHBpfVxmcmFje1xiZXRhfXtcYmV0YV4yICsgKHggLSBcYWxwaGEpXjJ9DQpcZW5ke2VxdWF0aW9ufQ0KYGBgDQpUaGlzIHBkZiBjb3JyZXNwb25kcyB0byB0aGUgQ2F1Y2h5IGRpc3RyaWJ1dGlvbi4NCg0KTm93LCBzaW5jZSB3ZSBkbyBub3Qga25vdyAkXGFscGhhJCBub3IgJFxiZXRhJCwgd2UgZXN0aW1hdGUgdGhlaXIgcHJpb3IuDQpBcyAkXGFscGhhIFxwZXJwIFxiZXRhJCwgdGhlIHBvc3RlcmlvciBpcyBvZiB0aGUgZm9ybToNCg0KYGBgez10ZXh9DQpcYmVnaW57ZXF1YXRpb259DQpQKFxhbHBoYSxcYmV0YSB8e3hfa30pIFxwcm9wdG8gUCh7eF9rfXxcYWxwaGEsXGJldGEpUChcYWxwaGEpUChcYmV0YSkNClxlbmR7ZXF1YXRpb259DQpgYGANCkFzc3VtaW5nICRcYWxwaGEkIGlzIHVuaWZvcm0gb3ZlciB0aGUgc2VnbWVudCAkW3hfe21pbn0sXCB4X3ttYXh9XSQsDQppLmUuICRwKFxhbHBoYSkgPSBcZnJhY3sxfXt4X3ttYXh9IC0geF97bWlufX0kOyBhbmQgJFxiZXRhJCBpcyB1bmlmb3JtDQpvdmVyIHRoZSBzZWdtZW50ICRbMCwgeV97bWF4fV0kLCBpLmUuICRwKFxiZXRhKSA9IFxmcmFjezF9e3lfe21heH19JC4NClRoZW4sIHRoZSBwb3N0ZXJpb3IgaXMgcHJvcG9ydGlvbmFsIHRvIHRoZSBsaWtlbGlob29kOg0KDQpgYGB7PXRleH0NClxiZWdpbntlcXVhdGlvbn0NClAoXGFscGhhLFxiZXRhIHx7eF9rfSkgXHByb3B0byBQKHt4X2t9fFxhbHBoYSxcYmV0YSkNClxlbmR7ZXF1YXRpb259DQpgYGANCkZvciB0aGUgbGlrZWxpaG9vZCwgd2UgY29uc2lkZXIgZWFjaCBzYW1wbGUgb2YgdGhlIGRhdGEgdG8gYmUgaWlkIGFuZCwNCnRoZXJlZm9yZToNCg0KYGBgez10ZXh9DQpcYmVnaW57ZXF1YXRpb259DQpQKHt4X2t9fFxhbHBoYSxcYmV0YSkgPSBccHJvZF97az0xfV57Tn0gUCh4X2t8XGFscGhhLFxiZXRhKQ0KXGVuZHtlcXVhdGlvbn0NCmBgYA0KYGBge3J9DQojIEdlbmVyYXRlIGRhdGFzZXQNCnNldC5zZWVkKDQxODMpDQojIHRydWUgdmFsdWVzDQphIDwtIDEwOyBiIDwtIDEwOw0KTiA8LSAyMDANCnRoZXRhIDwtIHJ1bmlmKE4sIC1waS8yLCBwaS8yKQ0KeC5rIDwtIGEqdGFuKHRoZXRhKSArIGENCmBgYA0KDQpgYGB7cn0NCiNTZXQgdGhlIHByb2JsZW0gZGF0YQ0KeC5taW4gPC0gLTIwMDAgI20NCngubWF4IDwtIDIwMDAgI20NCnkubWF4IDwtIDUwMDAgI20NCg0KYWxwaGFzIDwtIHNlcSh4Lm1pbiwgeC5tYXgsIDIwKQ0KYmV0YXMgPC0gc2VxKDAsIHkubWF4LCAyMCkNCmBgYA0KDQpgYGB7cn0NCiMgTG9nYXJpdGhtaWMgcG9zdGVyaW9yDQpsb2cucG9zdGVyaW9yIDwtIGZ1bmN0aW9uKHguaywgYWxwaCwgYmV0KSB7DQogIHN1bShsb2coKGJldCkvKHBpKihiZXQqKjIgKyAoeC5rLWFscGgpKioyKSkpKQ0KfQ0KDQpmLmF1eCA8LSBmdW5jdGlvbiAoYSwgYil7IGxvZy5wb3N0ZXJpb3IoeC5rLCBhLCBiKSB9DQoNCiMgRXZhbHVhdGUgZm9yIGFsbCBwb3NzaWJsZSBwYXJhbWV0ZXIgY29tYmluYXRpb25zIA0KbG9nLmdyaWQgPC0gb3V0ZXIoYWxwaGFzLCBiZXRhcywgVmVjdG9yaXplKGYuYXV4KSkNCg0KIyBQb3N0ZXJpb3JzIHNoYXBlDQojIEluZGl2aWR1YWwgcG9zdGVyaW9yIChrbm93biBhbHBoYSkNCmxvZy5wb3N0ZXJpb3IuaW5kIDwtIGZ1bmN0aW9uICh4LmssIGIpIHsNCiAgVmVjdG9yaXplKGZ1bmN0aW9uKGFfKSB7DQogICAgc3VtKGxvZyhiLyhwaSooYioqMiArICh4LmstYV8pKioyKSkpKQ0KICB9KQ0KfQ0KDQpscG9zIDwtIGxvZy5wb3N0ZXJpb3IuaW5kKHguaywgYSkNCg0KIyBOb3JtYWxpemUgYW5kIGV4cG9uZW50aWF0ZQ0Kc2hhcGUucG9zdGVyaW9yIDwtIGZ1bmN0aW9uICh4LCBscG9zKSB7DQogIGxvZy5hbHBoYXMgPC0gbHBvcyh4KQ0KICBsb2cubWF4YWxwaGEgPC0gbWF4KGxvZy5hbHBoYXMpDQogIHJldHVybiAoZXhwKGxvZy5hbHBoYXMgLSBsb2cubWF4YWxwaGEpKQ0KfQ0KDQojIE9idGFpbiB0aGUgcmVzdWx0cw0KZ3JpZC52YWx1ZXMgPC0gbWF0cml4KHNoYXBlLnBvc3Rlcmlvcihsb2cuZ3JpZCwgbHBvcyksIA0KICAgICAgICAgICAgICAgICAgICAgIG5yb3cgPSBsZW5ndGgoYWxwaGFzKSwgbmNvbCA9IGxlbmd0aChiZXRhcykpDQpgYGANCg0KYGBge3J9DQpmaWcgPC0gcGxvdF9seSh0eXBlID0gJ3N1cmZhY2UnLHggPSBhbHBoYXMsIHkgPSBiZXRhcywgeiA9IGdyaWQudmFsdWVzKQ0KZmlnIDwtIGxheW91dChmaWcsIHNjZW5lID0gbGlzdCh5YXhpcyA9IGxpc3QodGl0bGUgPSAnSGVpZ2h0IChtKScscmFuZ2U9YygxOTAwLDIxMDApKSwgeGF4aXMgPSBsaXN0KHRpdGxlID0gJ0xvY2F0aW9uIChtKScscmFuZ2UgPSBjKC0yMDAwLC0xOTAwKSksIHpheGlzID0gbGlzdCh0aXRsZSA9ICdQREYnKSkpDQoNCmZpZw0KYGBgDQoNCg0KYGBge3J9DQoNCm1heCA9IHdoaWNoKGdyaWQudmFsdWVzID09IG1heChncmlkLnZhbHVlcyksIGFyci5pbmQgPSBUUlVFKQ0KbWF4LmFscGhhIDwtIGFscGhhc1ttYXhbMSwyXV0NCm1heC5iZXRhIDwtIGJldGFzW21heFsxLDFdXQ0KbWVzc2FnZSgnVGhlIHBvc2l0aW9uIG9mIHRoZSBsaWdodGhvdXNlIGlzICcsIChtYXguYWxwaGEpLzEwMDAsJ2ttIGFsb25nIHRoZSBzaG9yZSBhbmQgJywgbWF4LmJldGEvMTAwMCwgJ2ttIG91dCBhdCBzZWEuJykNCmBgYA0KDQotLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0NCg0KIyMgRXhlcmNpc2UgMw0KDQpHaXZlbiB0aGUgU2lnbmFsIG92ZXIgQmFja2dyb3VuZCBleGFtcGxlIGRpc2N1c3NlZCBsYXN0IHdlZWssIGFuYWx5emUNCmFuZCBkaXNjdXNzIHRoZSBmb2xsb3dpbmcgY2FzZXM6DQoNCihhKSB2YXJ5IHRoZSBzYW1wbGluZyByZXNvbHV0aW9uIG9mIHVzZWQgdG8gZ2VuZXJhdGUgdGhlIGRhdGEsIGtlZXBpbmcNCiAgICB0aGUgc2FtZSBzYW1wbGluZyByYW5nZSB4ZGF0IFw8LSBzZXEoZnJvbT0tNyp3LCB0bz03KncsIGJ5PTAuNVwqdykg4oCiDQogICAgY2hhbmdlIHRoZSByZXNvbHV0aW9uIHcgPSB7MC4xLCAwLjI1LCAxLCAyLCAzfSDigKIgQ2hlY2sgdGhlIGVmZmVjdCBvbg0KICAgIHRoZSByZXN1bHRzDQoNCmBgYHtyfQ0KIyBHZW5lcmF0aXZlIG1vZGVsDQpzaWduYWwgPC0gZnVuY3Rpb24oeCwgYSwgYiwgeDAsIHcsIHQpIHsNCiAgdCAqIChhKmV4cCgtKCh4LXgwKSoqMikvKDIqdyoqMikpICsgYikNCn0NCg0KIyBEZWZpbmUgbW9kZWwgcGFyYW1ldGVycw0KeDAgPC0gMCAjIFNpZ25hbCBwZWFrDQp3LnJhbmdlIDwtIGMoMC4xLCAwLjI1LCAxLCAyLCAzKSAjIFNpZ25hbCB3aWR0aA0KQS50cnVlIDwtIDIgIyBTaWduYWwgYW1wbGl0dWRlDQpCLnRydWUgPC0gMSAjIEJhY2tncm91bmQgYW1wbGl0dWRlDQpEZWx0YS50IDwtIDUgIyBFeHBvc3VyZSB0aW1lDQoNCiMgU2FtcGxpbmcgZ3JpZCBmb3IgY29tcHV0aW5nIHBvc3Rlcmlvcg0KYWxpbSA8LSBjKDAuMCwgNC4wKQ0KYmxpbSA8LSBjKDAuNSwgMS41KQ0KTnNhbXAgPC0gMTAwDQp1bmlHcmlkIDwtIHNlcShmcm9tPTEvKDIqTnNhbXApLA0KdG89MS0xLygyKk5zYW1wKSwgYnk9MS9Oc2FtcCkNCmRlbHRhX2EgPC0gZGlmZihhbGltICkvIE5zYW1wDQpkZWx0YV9iIDwtIGRpZmYoYmxpbSApLyBOc2FtcA0KYSA8LSBhbGltWzFdICsgZGlmZihhbGltICkqIHVuaUdyaWQNCmIgPC0gYmxpbVsxXSArIGRpZmYoYmxpbSApKiB1bmlHcmlkDQoNCiMgTG9nIHBvc3Rlcmlvcg0KbG9nLnBvc3QgPC0gZnVuY3Rpb24oZCwgeCwgYSwgYiwgeDAsIHcsIHQpIHsNCiAgaWYoYTwwIHx8IGIgPDApIHtyZXR1cm4oLUluZiApfSAjIHRoZSBlZmZlY3Qgb2YgdGhlIHByaW9yDQogIHN1bShkcG9pcyhkLCBsYW1iZGE9c2lnbmFsKHgsIGEsIGIsIHgwLCB3LCB0KSwgbG9nPVRSVUUpKQ0KfQ0KDQojIEdlbmVyYXRlIHRoZSBvYnNlcnZlZCBkYXRhDQpzZXQuc2VlZCgxMjMpDQpmb3IgKHcgaW4gdy5yYW5nZSl7DQogIHhkYXQgPC0gc2VxKGZyb209LTcqdywgdG89Nyp3LCBieT0wLjUqdykNCiAgDQogIHMudHJ1ZSA8LSBzaWduYWwoeGRhdCAsIEEudHJ1ZSAsIEIudHJ1ZSAsIHgwLCB3LCBEZWx0YS50KQ0KICBkZGF0IDwtIHJwb2lzKGxlbmd0aChzLnRydWUpLCBzLnRydWUpDQogIHhwbG90IDwtIHNlcShmcm9tPW1pbih4ZGF0KSwgdG89bWF4KHhkYXQpLCBieT0wLjA1KncpDQogIHNwbG90IDwtIHNpZ25hbCh4cGxvdCAsIEEudHJ1ZSAsIEIudHJ1ZSAsIHgwLCB3LCBEZWx0YS50KQ0KICBvcHRpb25zKHJlcHIucGxvdC53aWR0aD0xNCwgcmVwci5wbG90LmhlaWdodD0xMCkgICN0byBzZXQgZ3JhcGggc2l6ZQ0KICBwYXIobWZyb3c9YygxLDIpKQ0KICBwbG90KHhwbG90ICwgc3Bsb3QgLCB4bGFiPSJ4IiwgeWxhYj0iU2lnbmFsK0JhY2tncm91bmQgY291bnRzIiwgeWxpbT1jKDIsIDI0KSkNCiAgI3BhcihuZXc9VFJVRSkNCiAgeGRhdC5vZmYgPC0geGRhdCAtIDAuMjUNCiAgbGluZXMoeGRhdC5vZmYsIGRkYXQgLCB0eXBlPSdzJyxjb2w9J2ZpcmVicmljazMnLCBsd2Q9Mix4bGltPXJhbmdlKHhwbG90KSwgeWxpbT1yYW5nZShjKHNwbG90ICwgZGRhdCApKSkNCiAgDQogICMgQ29tcHV0ZSBsb2cgdW5ub3JtYWxpemVkIHBvc3RlcmlvciAsIHogPSBsbiBQy4YqKGEsYnxEKSwgb24gYSByZWd1bGFyIGdyaWQNCiAgeiA8LSBtYXRyaXgoZGF0YT1OQSAsIG5yb3c9bGVuZ3RoKGEpLCBuY29sPWxlbmd0aChiKSkNCiAgZm9yKGogaW4gMTpsZW5ndGgoYSkpIHsNCiAgICBmb3IoayBpbiAxOmxlbmd0aChiKSkgew0KICAgICAgeltqLGtdIDwtIGxvZy5wb3N0KGRkYXQgLCB4ZGF0ICwgYVtqXSwgYltrXSwgeDAsIHcsIERlbHRhLnQpDQogICAgfQ0KICB9DQogIHogPC0geiAtIG1heCh6KSAjIHNldCBtYXhpbXVtIHRvIHplcm8NCiAgIyBQbG90IHVubm9ybWFsaXplZCAyRCBwb3N0ZXJpb3IgYXMgY29udG91cnMuDQogIGNvbnRvdXIoYSwgYiwgZXhwKHopLA0KICAgICAgICAgIG5sZXZlbHMgPSA1LA0KICAgICAgICAgIGxhYmNleCA9IDAuNSwNCiAgICAgICAgICBsd2QgPSAyLA0KICAgICAgICAgIHhsYWI9ImFtcGxpdHVkZSAsIEEiLA0KICAgICAgICAgIHlsYWI9ImJhY2tncm91bmQgLCBCIikNCiAgYWJsaW5lKHY9MixoPTEsY29sPSJncmV5IikNCn0NCg0KDQpgYGANCg0KKGIpIGNoYW5nZSB0aGUgcmF0aW8gQS9CIHVzZWQgdG8gc2ltdWxhdGUgdGhlIGRhdGEgKGtlZXBpbmcgYm90aA0KICAgIHBvc2l0aXZlIGluIGFjY29yZGFuY2Ugd2l0aCB0aGUgcHJpb3IpIOKAoiBDaGVjayB0aGUgZWZmZWN0IG9uIHRoZQ0KICAgIHJlc3VsdHMNCg0KYGBge3J9DQoNCiMgRGVmaW5lIG1vZGVsIHBhcmFtZXRlcnMNCngwIDwtIDAgIyBTaWduYWwgcGVhaw0Kdy5yYW5nZSA8LSAxICMgU2lnbmFsIHdpZHRoDQpBLnRydWUgPC0gNCAjIFNpZ25hbCBhbXBsaXR1ZGUNCkIudHJ1ZSA8LSAxICMgQmFja2dyb3VuZCBhbXBsaXR1ZGUNCkRlbHRhLnQgPC0gNSAjIEV4cG9zdXJlIHRpbWUNCg0KeGRhdCA8LSBzZXEoZnJvbT0tNyp3LCB0bz03KncsIGJ5PTAuNSp3KQ0KICANCnMudHJ1ZSA8LSBzaWduYWwoeGRhdCAsIEEudHJ1ZSAsIEIudHJ1ZSAsIHgwLCB3LCBEZWx0YS50KQ0KZGRhdCA8LSBycG9pcyhsZW5ndGgocy50cnVlKSwgcy50cnVlKQ0KeHBsb3QgPC0gc2VxKGZyb209bWluKHhkYXQpLCB0bz1tYXgoeGRhdCksIGJ5PTAuMDUqdykNCnNwbG90IDwtIHNpZ25hbCh4cGxvdCAsIEEudHJ1ZSAsIEIudHJ1ZSAsIHgwLCB3LCBEZWx0YS50KQ0Kb3B0aW9ucyhyZXByLnBsb3Qud2lkdGg9MTQsIHJlcHIucGxvdC5oZWlnaHQ9MTApICAjdG8gc2V0IGdyYXBoIHNpemUNCnBhcihtZnJvdz1jKDEsMikpDQpwbG90KHhwbG90ICwgc3Bsb3QgLCB4bGFiPSJ4IiwgeWxhYj0iU2lnbmFsK0JhY2tncm91bmQgY291bnRzIiwgeWxpbT1jKDAsIDQwKSkNCiNwYXIobmV3PVRSVUUpDQp4ZGF0Lm9mZiA8LSB4ZGF0IC0gMC4yNQ0KbGluZXMoeGRhdC5vZmYsIGRkYXQgLCB0eXBlPSdzJyxjb2w9J2ZpcmVicmljazMnLCBsd2Q9Mix4bGltPXJhbmdlKHhwbG90KSwgeWxpbT1yYW5nZShjKHNwbG90ICwgZGRhdCApKSkNCg0KIyBDb21wdXRlIGxvZyB1bm5vcm1hbGl6ZWQgcG9zdGVyaW9yICwgeiA9IGxuIFDLhiooYSxifEQpLCBvbiBhIHJlZ3VsYXIgZ3JpZA0KeiA8LSBtYXRyaXgoZGF0YT1OQSAsIG5yb3c9bGVuZ3RoKGEpLCBuY29sPWxlbmd0aChiKSkNCmZvcihqIGluIDE6bGVuZ3RoKGEpKSB7DQogIGZvcihrIGluIDE6bGVuZ3RoKGIpKSB7DQogICAgeltqLGtdIDwtIGxvZy5wb3N0KGRkYXQgLCB4ZGF0ICwgYVtqXSwgYltrXSwgeDAsIHcsIERlbHRhLnQpDQogIH0NCn0NCnogPC0geiAtIG1heCh6KSAjIHNldCBtYXhpbXVtIHRvIHplcm8NCiMgUGxvdCB1bm5vcm1hbGl6ZWQgMkQgcG9zdGVyaW9yIGFzIGNvbnRvdXJzLg0KY29udG91cihhLCBiLCBleHAoeiksDQogICAgICAgIG5sZXZlbHMgPSA0LA0KICAgICAgICBsYWJjZXggPSAwLjUsDQogICAgICAgIGx3ZCA9IDIsDQogICAgICAgIHhsYWI9ImFtcGxpdHVkZSAsIEEiLA0KICAgICAgICB5bGFiPSJiYWNrZ3JvdW5kICwgQiIsDQogICAgICAgIHhsaW0gPSBjKDAsNSkpDQphYmxpbmUodj00LGg9MSxjb2w9ImdyZXkiKQ0KDQoNCmBgYA0K